/**
 * @class   wosh::BusManager
 * @brief   CoreModule designed to manage busses (wosh::Bus), their creation and connections.
 *          It also interacts with wosh::NetworkManager for wosh::Message routing.
 *
 * \image html diagrams/BusManager.png "wosh::BusManager UML diagram"
 *
 *
 * @ingroup CoreModules
 ****************************************************************************
 * @version 0.8.499 $Id: BusManager.h 2873 2010-08-08 19:06:41Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/*! \page page_core
 * \htmlonly <hr/> \endhtmlonly
 * \section page_core_busses Busses
 *
 * wosh::BusManager service manages wosh:Bus instances, their life cycle and events.
 *
 * WOSH is a Message-Oriented Middleware.
 *
 * Bundles interacts each other sending and evaluating wosh::Message objects.
 * wosh::Message is a generic container, it holds:
 *  - content of the message (request, response, fact, ..)
 *  - routing information (source, target, hops)
 *  - security information (creator user)
 *
 * \image html diagrams/Message.png "wosh::Message UML diagram"
 *
 *
 * The source code required to send a request message is:
 * \code
Message* message = new Message( new Request(_METHOD_ListProperties) );
message->setSource(this);
message->getDestination().fromString( "wosh1:Bundles/GTalkBot" );
BusCore.postMessage(message);
 * \endcode
 *
 *
 * There are more Busses on a generic WoshKernel, some of them are always available
 * because are allocated by the kernel or its modules:
 *  - wosh.Bus.Core - created by wosh::WoshKernel
 *  - wosh.Bus.Devices - created by wosh::DeviceManager
 *  - wosh.Bus.Security - created by wosh::SecurityManager
 *
 * wosh::BusManager provides some basic message routing functionalities.
 *
 *
 * wosh::Message pushing is asynchronous and it can't guarantee that Messages are received.
 * Messages are notified to the (listening) bundles by the Bus.
 * 
 * wosh::Bus is the interface of a generic Messages Dispatcher.
 * Built-in implementation are:
 *  - wosh::BusRing is a single thread implementation, which loops listeners delivering
 *    the current message.
 *
 *  - wosh::BusMT is a multi-thread (N+1) implementation using a hierarchical process resilience.
 *    Each worker dispatches a message to all listeners, more workers (N) run at same time.
 *    The coordinator thread loops the message queue and assign current message to first available worker.
 *    The order of messages' arrival is not predictable.
 *
 * wosh::BusConnector is an helper object which simplifies the implementation, the code
 * required to register to the \c Core bus is:
 * \code
BusCore.setMessageHandler(this);
WRESULT bus_connected = BusCore.connect( _Bus_Core );
 * \endcode
 *
 * The object (*this) implements the wosh::IBusListener interface (for receiving messages):
 * \code
void BundleGeneric::busMessage( const Message& message, Bus* source ) {
	if ( message.isEmpty() ) return;
	if ( !MessageFilter::isMessageTarget(message, this) )
		return;
	if ( !message.getContent()->isRequest() )
		return;
	Message* reply = MPC_busMessageRequest( message, this->Methods, this->Log );
	if ( reply == NULL )
		return;
	BusCore.postMessage(reply);
 }
 * \endcode
 *
 * Few notes:
 *  - Message instance (reference) is lost on \c postMessage() call (ownership
 *    of the message moves to the Bus)
 *  - The processing is done by Bus' thread!
 *    When the processing takes long time or it is 'dangerous' (potential crash)
 *    it must be done in another thread, so the Bus won't be busy or damaged by
 *    service's implementation. This is usually done filtering incoming messages
 *    and appending to an internal queue which is processed by (another) internal thread.
 *
 *
 * \see wosh::BusManager
 * \see wosh::Bus
 * \see wosh::BusRing
 * \see wosh::BusMT
 *
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR BusS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_BusManager_H__
 #define __WOSH_Core_BusManager_H__

 #include <woshDefs.h>
 #include <core/WoshModule.h>

 #include <core/Containers.h>
 #include <core/Bus.h>


namespace wosh {

 #define _BusManager_NAME					"BusManager"
 #define _BusManager_URI					":Busses"

 #define _BusManager_METHOD_create_bus		"create_bus"
 #define _BusManager_METHOD_control_bus		"control_bus"

class Message;
class NetworkChannel;
class NetworkManager;
class WoshKernel;


class BusManager : public WoshModule
 {
	WOSH_MODULE(wosh::BusManager)

	typedef MapT<std::string, wosh::Bus*> tStrBusMap;


	protected:
		/**
		 * @brief  Default constructor. Call base constructor and initialize some properties and hosted methods.
		 * @param parent [in] WoshKernel singleton, passed to WoshModule constructor
		 * @note   Called by WoshKernel only. Static getter (gamma singleton) will return NULL until kernel is created.
		 */
		BusManager( const WoshKernel* parent = NULL );

		/**
		 * @brief  Call base class implementation.
		 * @return result of WoshModule::onKernelInitializing()
		 */
		WRESULT onKernelInitializing();
		/**
		 * @brief  Stop any running bus synchronously (30 seconds timeout) and call base class implementation.
		 * @return result of stopBusses() + WoshModule::onKernelInitializing()
		 * @see    stopBusses()
		 */
		WRESULT onKernelStopped();

		/**
		 * @brief  Stop all (registered) running busses. Reentrant.
		 * @param  timeout [in] timeout in milliseconds, 0 means asynch call; default is no timeout
		 * @return WRET_OK if no busses are running or all have been successfully stopped, sumOf[WRESULT of stopBus()] else
		 * @note   timeout is forwarded: it is not considered as the global timeout, but as timeout for-each bus-stop)
		 */
		WRESULT stopBusses( unsigned long timeout = LIMIT_ULONG_MAX );

		friend class wosh::WoshKernel;

	public:
		/**
		 * @brief  Destructor. If any Bus is still running, it is stopped (synch, 20 second timeout for each bus)
		 *         All registered busses are destroyed.
		 */
		virtual ~BusManager();

//@}
/** @name Public methods
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get the number of busses. Reentrant.
		 * @return the number of registered busses
		 */
		inline int count() const				{ return this->busses.count(); }
		/**
		 * @brief  Get the number of running busses. Reentrant.
		 * @return the number of registered busses that are running (Bus::STATE_STARTED)
		 */
		int countRunning() const;
		/**
		 * @brief  Get the number of non-running threads. Reentrant.
		 * @return the number of registered threads that are NOT running
		 */
		inline int countStopped() const			{ return count() - countRunning(); }
		/**
		 * @brief  Evaluate if bus is registered. Reentrant.
		 * @param  busname [in] name of the bus to be found
		 * @return true if a bus with same name is registered; false else
		 */
		bool existsBus( const std::string& busname ) const;

		/**
		 * @brief  Register (add) a new Bus. Only reference is stored, no copy operations. Reentrant.
		 * @param  bus_ptr [in] pointer of the Bus to be added
		 * @return WRET_ERR_PARAM when bus is NULL or already registered (pointer lookup). WRET_OK else
		 * @see    registerBus_()
		 */
		WRESULT registerBus( Bus* bus_ptr );

		/**
		 * @brief  Create a new Bus. Reentrant.
		 * @param  busname [in] name to be assigned to the bus
		 * @param  bus_type [in] full classname, allocated by ObjectFactory, by default _BusRing_TYPE
		 * @return WRET_ERR_PARAM when busname is too short (3 chars) or if a bus with same name exists. WRET_OK else
		 * @see    registerBus_()
		 */
		WRESULT createBus( const std::string& busname, const std::string& bus_type = "" );

		/**
		 * @brief  Connect handler (listener) to a Bus.
		 * @param  handler [in] pointer to the handler (listener) to connect
		 * @param  busname [in] name of the bus to be connected to
		 * @return WRET_ERR_PARAM when busname is too short (3 chars) or if a bus with same name exists. WRET_OK else
		 */
		WRESULT connectBus( IBusListener* handler, const std::string& busname, int connection_options = Bus::BUS_NO_OPTIONS );

		/**
		 * @brief  Disconnect a Listener from one or more Bus(ses). Reentrant.
		 * @param  handler [in] pointer to the handler (listener) to be unregistered
		 * @param  busname [in] name of the bus to be removed from, empty names means any bus
		 * @return WRET_ERR_PARAM when busname is too short (3 chars) or if a bus with same name exists. WRET_OK else
		 * @see    registerBus_()
		 */
		WRESULT disconnectBus( IBusListener* handler, const std::string& busname = "*", int connection_options = Bus::BUS_NO_OPTIONS );

		/**
		 * @brief  Push a message to a local (registered) bus
		 * @param  message [in] pointer of the message, object is acquired (caller lose ownership)
		 * @param  busname [in] name of the target bus
		 * @return WRET_ERR_PARAM if the bus was not found; WRET_OK else
		 */
		WRESULT postMessage( Message* message, const std::string& busname );

//@}
/** @name Bus Events (state-change)
 * @{
 ******************************************************************************/
	protected:
		/**
		 * @brief  Raise (internal) events from (base) Bus instances.
		 * @param  bus_state [in] the new state
		 * @param  mbus [in] pointer to the source of the event
		 * @see    BusManager::mbus_event()
		 */
		static inline void push_event( Bus::BUS_STATE bus_state, Bus* mbus ) {
			BusManager* instance = BusManager::getInstance();
			if ( instance == NULL ) return;
			instance->mbus_event( bus_state, mbus );
		 }
		/**
		 * @brief  Push a message from a local bus to another local/remote bus(ses).
		 *         The message is routed to other bus/hosts.
		 * @param  message [in] pointer of the message, message is eventually copied
		 * @param  source [in] pointer to the source bus
		 * @note   used by NetworkManager only
		 */
		static void push_message( const Message* message, Bus* source );

		friend class wosh::Bus;
//@}
/** @name NetworkManager Events (push messages)
 * @{
 ******************************************************************************/
	protected:
		/**
		 * @brief  Push a message into local bus(ses) from a Network Channel.
		 *         The message may be broadcasted to all registered busses (when DestinationBus==_Bus_ANY)
		 *         or directly to destination bus.
		 * @param  message [in] pointer of the message, object is acquired (caller lose ownership)
		 * @param  source [in] pointer to the source channel
		 * @note   used by NetworkManager only
		 */
		static void push_message( Message* message, NetworkChannel* source );

		friend class wosh::NetworkManager;
//@}
/** @name BusConnector Events (connect to Bus)
 * @{
 ******************************************************************************/
	protected:
		/**
		 * @brief  Connect handler (listener) to a Bus, eventually creating it.
		 * @param  handler [in] pointer to the handler (listener) to connect
		 * @param  busname [in] name of the bus to be connected to
		 * @param  create_if_required [in] auto-creation flag: if true and the bus is missing,
		 *         then create a new Bus of type wosh::BusRing
		 * @return pointer to Bus just created. May be NULL
		 * @warning this is BAD since the bus may be destroyed while the caller is using it!
		 * @note   used by BusConnector only
		 */
		Bus* connectBusEx( IBusListener* handler, const std::string& busname, int connection_options );

		friend class wosh::BusConnector;
//@}
/** @name Internal Mehods and Events management
 * @{
 ******************************************************************************/
	private:
		/**
		 * @brief  Access the BusManager singleton. Gamma Pattern.
		 *         Static reference is allocated and detroyed by WoshKernel on constructor/destructor respectively
		 * @return pointer to BusManager singleton. May be NULL (if kernel has not been allocated yet)
		 */
		static BusManager* getInstance();

	private:
		/**
		 * @brief  Manage Bus state-change event, pushed internally.
		 * @param  bus_state [in] the new state
		 * @param  mbus [in] pointer to the source of the event
		 * @see    push_event()
		 */
		void mbus_event( Bus::BUS_STATE bus_state, Bus* mbus );

		/**
		 * @brief  Register (add) a new Bus. Only reference is stored, no copy operations. NOT reentrant.
		 * @param  bus [in] pointer of the Bus to be added
		 * @return WRET_ERR_PARAM when bus is NULL or already registered (pointer lookup). WRET_OK else
		 * @see    mbus_event()
		 */
		WRESULT registerBus_( Bus* bus );
		/**
		 * @brief  UnRegister (remove) a new Bus. Only entry is removed, no operation on bus. NOT reentrant.
		 * @param  bus [in] pointer of the Bus to be removed
		 * @return WRET_ERR_PARAM when bus is NULL or not-found (pointer lookup). WRET_OK else
		 * @see    thread_event()
		 */
		WRESULT unRegisterBus_( Bus* bus );

		/**
		 * @brief  Count running busses. NOT reentrant.
		 * @return number of registered busses in Bus::STATE_STARTED state
		 */
		int countRunning_() const;
//@}
	private:
		Response* mmDoCreateBus( const Request* request );
		Response* mmDoControlBus( const Request* request );

	private:
		tStrBusMap busses;	///< map of pairs<name,Bus*>, instance are auto-(un)registered


}; // class def

}; // namespace wosh

#endif //__WOSH_Core_BusManager_H__
